/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import micromatch from 'micromatch';
import ejs from 'ejs';
import { Logger, PluginFileUtil, PluginStore, StringUtil } from '../../framework';
import { HMRouterResult, TemplateModel } from '../model';
import { CustomPageTemplateImpl } from '../config/HMRouterPluginConfig';
import { HMRouterExtensionContext } from '../HMRouterExtensionContext';
import { ErrorCode, PluginError } from '../error/PluginError';
import {
  AnnotationConstants,
  FilePathConstants,
  PrefixConstants,
  TemplateConstants,
  VersionConstants,
} from '../constants';

/**
 * 代码生成钩子
 * 负责根据注解生成页面文件
 */
export class CodeGenerationProcessor {
  private context: HMRouterExtensionContext;
  private sdkVersion: number = 0;

  constructor(context: HMRouterExtensionContext) {
    this.context = context;
  }

  /**
   * 执行代码生成
   */
  execute(): void {
    this.sdkVersion = this.getCompileSdkVersion();
    Logger.debug(this.context.node.getNodeName(), `Start to code generation...`);

    this.context.generatedPaths = new Map<string, string>();

    this.context.getAnalyzeResults<HMRouterResult>().forEach((result: HMRouterResult) => {
      if (result.annotation === AnnotationConstants.ROUTER_ANNOTATION) {
        if (!result.sourceFilePath) {
          throw PluginError.create(
            ErrorCode.ERROR_PAGE_SOURCE_FILE,
            this.context.config.moduleName,
            result.sourceFilePath
          );
        }

        let pageSourceFile = this.context.config
          .getRelativeSourcePath(result.sourceFilePath)
          .replaceAll(FilePathConstants.FILE_SEPARATOR, FilePathConstants.DELIMITER);

        this.generatePageFile(
          result,
          pageSourceFile,
          this.matchedPath(
            pageSourceFile,
            this.context.config.customPageTemplate,
            this.context.config.getDefaultTplFilePath()
          )
        );
      }
    });
  }

  /**
   * 从compatibleSdkVersion中提取版本号
   * @param compatibleSdkVersion 可能是字符串（如"5.0.5(17)"）或数字（如12）
   * @returns 提取的版本号数字
   */
  extractVersion(compatibleSdkVersion: string | number): number {
    if (typeof compatibleSdkVersion === 'number') {
      return compatibleSdkVersion;
    } else {
      // 提取括号中的数字
      const match = compatibleSdkVersion.match(/\((\d+)\)/);
      if (match && match[1]) {
        return parseInt(match[1], 10);
      }

      // 尝试直接转换为数字
      const num = parseFloat(compatibleSdkVersion);
      if (!isNaN(num) && num > FilePathConstants.DEFAULT_VALUE) {
        return num;
      }

      return FilePathConstants.DEFAULT_VALUE;
    }
  }

  /**
   * 从JSON5字符串中读取compileSdkVersion并提取版本号
   * @param json5String JSON5格式的字符串
   * @returns 提取的版本号数字
   */
  getCompileSdkVersion(): number {
    let json5FilePath = '';
    let sdkVersion = FilePathConstants.DEFAULT_VALUE;
    let arrData = ['DEVECO_SDK_HOME', 'HOS_SDK_HOME', 'OHOS_SDK_HOME'];

    
    for (let index = 0; index <= 4; index++) {
      // 提取路径
      if (index < 3 && process.env[arrData[index]]) {
        json5FilePath = PluginFileUtil.pathResolve(process.env[arrData[index]]!, FilePathConstants.SDK_HOME);
      } else if (index === 3) {
        json5FilePath = PluginFileUtil.pathResolve(PluginStore.getInstance().get<string>('projectFilePath')!,
          FilePathConstants.BUILD_PROFILE);
      } else if (index === 4) {
        json5FilePath = PluginFileUtil.pathResolve(PluginStore.getInstance().get<string>('projectFilePath')!,
          FilePathConstants.BUILD_PROFILE);
      }

      // 提取版本号
      const sdkVer = this.getSdkVersion(json5FilePath, index);
      if (sdkVer > FilePathConstants.DEFAULT_VALUE) {
        sdkVersion = sdkVer;
        break;
      }
    }

    return sdkVersion;
  }

  getSdkVersion(json5FilePath: string, index: number): number {
    if (PluginFileUtil.exist(json5FilePath)) {
      const data = PluginFileUtil.readJson5(json5FilePath);
      if (index < 3) {
        return this.extractVersion(data.apiVersion);
      } else if (index === 3) {
        if (data.app.products[0].compileSdkVersion) {
          return this.extractVersion(data.app.products[0].compileSdkVersion);
        }
      } else if (index === 4) {
        if (data.app.products[0].compatibleSdkVersion) {
          return this.extractVersion(data.app.products[0].compatibleSdkVersion);
        }
      }
    }

    return FilePathConstants.DEFAULT_VALUE;
  }

  /**
   * 生成页面文件
   * @param result 分析结果
   * @param pageSourceFile 页面源文件
   * @param tempFilePath 模板文件路径
   * @private
   */
  private generatePageFile(result: HMRouterResult, pageSourceFile: string, tempFilePath: string): void {
    // 准备模板数据
    const templateModel = this.prepareTemplateModel(result, pageSourceFile);

    // 检查库版本并确定模板路径
    tempFilePath = this.determineTemplatePath(result, tempFilePath);

    // 生成文件
    const generatedFilePath = this.generateFile(templateModel, tempFilePath);

    Logger.info(
      this.context.node.getNodeName(),
      `Builder ${templateModel.generatorViewName}.ets has been generated in ${generatedFilePath}`
    );

    // 将生成的文件路径添加到context中，使用组件名称+pageUrl作为唯一键避免冲突
    const uniqueKey = `${result.name}#${result.pageUrl}`;
    this.context.generatedPaths.set(uniqueKey, generatedFilePath);
  }

  /**
   * @description Match the template path based on the path and custom template rules, otherwise use the default value
   * @param filePath
   * @param customPageTemplate
   * @param defaultTplFilePath Default template path
   * @return string , Template path
   */
  private matchedPath(
    filePath: string,
    customPageTemplate: CustomPageTemplateImpl[],
    defaultTplFilePath: string
  ): string {
    for (const template of customPageTemplate) {
      if (micromatch.isMatch(filePath, template.srcPath)) {
        Logger.debug(
          this.context.node.getNodeName(),
          `${filePath} detected matching template: ${template.templatePath}`
        );
        return PluginFileUtil.pathResolve(this.context.config.configDir, template.templatePath);
      }
    }
    // Use the default value if no rule matches
    return defaultTplFilePath;
  }

  /**
   * @description 准备模板所需的数据模型
   * @param analyzeResult 分析结果
   * @param pageSourceFile 页面源文件
   * @return TemplateModel 模板数据模型
   */
  private prepareTemplateModel(analyzeResult: HMRouterResult, pageSourceFile: string): TemplateModel {
    // 获取导入路径
    let importPath = this.context.config
      .getRelativeBuilderPath(pageSourceFile)
      .replaceAll(FilePathConstants.FILE_SEPARATOR, FilePathConstants.DELIMITER)
      .replaceAll(FilePathConstants.ETS_SUFFIX, '');

    // 生成视图名称
    let generatorViewName =
      PrefixConstants.VIEW_NAME_PREFIX + analyzeResult.name + StringUtil.stringToHashCode(analyzeResult.pageUrl!);

    let templateData = this.context.getTemplateData(analyzeResult.name);

    // 创建模板模型
    return {
      sdkVersion: this.sdkVersion,
      pageUrl: analyzeResult.pageUrl,
      componentName: analyzeResult.name,
      dialog: !!analyzeResult.dialog,
      isDefaultExport: !!templateData?.isDefaultExport,
      importPath,
      generatorViewName,
      ...templateData,
    };
  }

  /**
   * @description 根据分析结果和库版本确定使用的模板路径
   * @param analyzeResult 分析结果
   * @param defaultTemplatePath 默认模板路径
   * @return string 确定后的模板路径
   */
  private determineTemplatePath(analyzeResult: HMRouterResult, defaultTemplatePath: string): string {
    // 检查hmrouter库的版本
    const libraryVersion = this.detectLibraryVersion();

    Logger.debug(this.context.node.getNodeName(), `Library version: ${libraryVersion}`);

    // 判断是否使用v1模板: 库版本是1.0.0
    const useV1Template = libraryVersion.startsWith(VersionConstants.HMROUTER_VERSION_V1);

    if (useV1Template) {
      return PluginFileUtil.pathResolve(__dirname,
        FilePathConstants.PARENT_DELIMITER.repeat(3) + TemplateConstants.V1_TEMPLATE
      );
    }
    // 检查是否有useNavDst参数并且为true，如果是则使用customBuilder.ejs模板
    else if (analyzeResult.useNavDst === true) {
      // 构建自定义模板路径，替换原来的模板路径
      return PluginFileUtil.pathResolve(
        __dirname,
        FilePathConstants.PARENT_DELIMITER.repeat(3),
        TemplateConstants.CUSTOM_BUILDER_TEMPLATE
      );
    }

    return defaultTemplatePath;
  }

  /**
   * @description 生成文件并返回路径
   * @param templateModel 模板数据模型
   * @param templatePath 模板文件路径
   * @return string 生成的文件路径
   */
  private generateFile(templateModel: TemplateModel, templatePath: string): string {
    // 检查模板文件是否存在
    if (!PluginFileUtil.exist(templatePath)) {
      throw PluginError.create(ErrorCode.TEMPLATE_NOT_FOUND, this.context.config.moduleName, templatePath);
    }

    // 读取模板并渲染
    const tpl = PluginFileUtil.readFileSync(templatePath).toString();
    const templateStr = ejs.render(tpl, templateModel);

    // 生成文件路径并写入文件
    const generatorFilePath = this.context.config.getGeneratedFilePath(templateModel.generatorViewName);
    PluginFileUtil.ensureFileSync(generatorFilePath);
    PluginFileUtil.writeFileSync(generatorFilePath, templateStr);

    // 返回生成的文件路径
    return this.context.config
      .getBuilderFilePath(templateModel.generatorViewName)
      .replaceAll(FilePathConstants.FILE_SEPARATOR, FilePathConstants.DELIMITER);
  }

  /**
   * @description 检测库版本
   * @return string 库版本号
   */
  private detectLibraryVersion(): string {
    let libraryVersion = '';

    // 获取可能的路径列表
    const possiblePaths = this.getLibraryPossiblePaths();

    // 遍历所有可能的路径
    for (const packagePath of possiblePaths) {
      libraryVersion = this.detectLibraryVersion2(packagePath);
      if (libraryVersion) {
        break; // 找到版本后立即退出
      }
    }

    return libraryVersion;
  }

  private detectLibraryVersion2(packagePath: string): string {
    let libraryVersion = '';
    try {
      if (PluginFileUtil.exist(packagePath)) {
        const packageJson = PluginFileUtil.readJson5(packagePath);
        libraryVersion = packageJson[VersionConstants.HMROUTER_VERSION_KEY] || '';
      }
    } catch (error) {
      // 继续检查下一个路径
    }
    return libraryVersion;
  }

  /**
   * @description 获取库可能安装的所有路径
   * @return string[] 可能的路径列表
   */
  private getLibraryPossiblePaths(): string[] {
    const paths: string[] = [];

    // 1. 模块级别的oh_modules
    paths.push(
      PluginFileUtil.pathResolve(
        this.context.config.modulePath,
        FilePathConstants.OH_MODULE_PATH,
        VersionConstants.HMROUTER_ORGANIZATION,
        VersionConstants.HMROUTER_LIB_NAME,
        FilePathConstants.OH_PACKAGE_FILE_NAME
      )
    );

    // 2. 工程级别的oh_modules
    const projectRoot = PluginStore.getInstance().get<string>('projectFilePath');
    if (projectRoot && projectRoot !== this.context.config.modulePath) {
      paths.push(
        PluginFileUtil.pathResolve(
          projectRoot,
          FilePathConstants.OH_MODULE_PATH,
          VersionConstants.HMROUTER_ORGANIZATION,
          VersionConstants.HMROUTER_LIB_NAME,
          FilePathConstants.OH_PACKAGE_FILE_NAME
        )
      );
    }

    return paths;
  }
}
